/*
 * Client request for File download via HTTP GET and download negotiation
 * 
 * A P2P client is a client of both the directory server and the P2P server. 
 * The P2P client provides a text-based user interface for a user to interact with the directory server. 
 * This is the minimal requirement and you are encouraged to implement a client with a nice GUI. 
 * With this interface, commands such as "inform", "query", and "exit" are issued and responses returned from the directory server are displayed. 
 * A user can then select a server from a list of P2P servers that have a desired file, 
 * and issue the HTTP GET command to retrieve desired MP3 files from the selected P2P server.
 *  No particular format is enforced on how to maintain the database of MP3 file entries at the directory server.
 * Similarly, no particular format is enforced for the query results of a directory listing request. 
 * However, the choices of these formats must be documented in the system documentation (detailed below),
 * which must clearly describe how to use the user interface to issue commands or to select a P2P server in the user documentation.
 * HTTP 1.1, as defined in RFC 2616, will be used to transmit MP3 files between a P2P client and a P2P server. 
 * Separate HTTP requests are sent for each MP3 file desired. 
 * A P2P server will be able to handle multiple simultaneous requests in parallel.
 * This means that the P2P server must be multi-threaded. 
 * In the main thread, the server listens to a fixed port.
 * When it receives a TCP connection request, it creates a new TCP socket and services the request in a separate thread.
 * The subset of HTTP 1.1 functionalities needed in this project is
 * Only GET request needs to be implemented. The URL field in GET method contains the name of the requested file
 * The server must implement HTTP code 200, 400, 404 and 505 correctly.
 */
package rapidp2p.backend;

/**
 *
 * @author Rudy
 */
import java.io.*;
import java.net.*;
import java.util.UUID;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class RequestFile {

    private Socket client;
    private String hostIP ; // IP of file host
    private int hostPort = 6789;
    private String fileName;  // requested file
    private String key;     // Unique key to identify this request
    private File saveDir = new File(System.getProperty("user.home") + "\\share\\");  // location to save file

    RequestFile(String filename) {
        this.fileName = filename;
    }

    public String key() {
        return this.key;
    }

    // Returns location of the save directory
    public String saveDirectory() {
        return this.saveDir.toString();
    }

    public void requestFile(String hostIP) {
        this.saveDir = new File(System.getProperty("user.home") + "//share//");
        this.hostIP = hostIP;
        // this.fileName = fileName;

        this.key = UUID.randomUUID().toString();

        if (!saveDir.exists()) {
            saveDir.mkdir();
        }
    }

    public void download() {

        //newsocket
        // InetSocketAddress Address = new InetSocketAddress(hostIP, hostPort); 
        try {
            ///this.client.connect(Address); //  http request version.. not needed

            client = new Socket(hostIP, hostPort);

            //in+out streams
            DataOutputStream outToServer = new DataOutputStream(client.getOutputStream());

            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(client.getInputStream()));


            //URIencode file name b4 send?

            // Compose HTTP Request
            String request = "GET/ " + this.fileName + " HTTP/1.1\r\n"
                    + "Host:" + this.hostIP + "\r\n"
                    + "User-Agent:Rapidp2pHost \r\n"
                    + "Connection:close\r\n"
                    + "\r\n";

            // Send Request
            outToServer.writeBytes(request);
            System.out.println("file request sent");

            // accept response + get status
            String delimiter = " ";
            String line1 = inFromServer.readLine();
            System.out.println("read first line of response  " + line1);

            String[] status = line1.split(delimiter, 3);
            String httpVersion = status[0];
            String httpCode = status[1];
            String httpPhrase = status[2];

            System.out.println("response from server received");

            if (httpCode.equals("200")) // OK
            {  // if status OK - read rest headers 
                Map<String, String> headers = new HashMap<String, String>();
                String lines = inFromServer.readLine();
                System.out.println("second line" + lines);
                String splitregex = "[:]";

                String[] parts = lines.split(splitregex);
         
                System.out.println("split second line");

                // then read bytes -> FileOutputStream (stream at data)
                System.out.println("Response Code: 200 OK - initiating download");
                String flength = parts[3];
                String transferPort = parts[1];
                System.out.println("length" +flength+ " /nport " + transferPort);
                Long length = Long.parseLong(flength);
                System.out.println("file lenght " + length);
                int tPort = Integer.parseInt(transferPort); // parse as correct type

                int bytesRead = 0;
                int bytesRem = length.intValue();
                // final file path
                File tempFile = new File(fileName);

                // final file path
                String filePath = this.saveDirectory() + File.separatorChar + tempFile.getName();
                filePath = filePath.replace("..", "");
                filePath = filePath.replace('/', File.separatorChar);
                filePath = filePath.replace('\\', File.separatorChar);
                System.out.println("Final resting spot:" + filePath);

                // downloaded filestream
                FileOutputStream fos = new FileOutputStream(filePath);



                System.out.println(" Beginning Download of " + fileName);

                //read data
                while (bytesRem > 0) {
                    byte[] buffer = new byte[(length.intValue())];
                    // NEED BYTES FROM SERVER NOT SURE IF CORRECT
                    int nr = client.getInputStream().read(buffer, 0, buffer.length);

                   if (nr == 0) {
                      break;  //EOF or Error
                    }
                    //write to file
                    fos.write(buffer, 0, nr);

                    bytesRead += nr;
                    bytesRem -= nr;
                    System.out.println("bytes read:" + bytesRead + "bytes remaining: " + bytesRem);
                }
                //close streams
                fos.close();
                inFromServer.close();
                //client.getInputStream().close();

                //copy file to final resting spot  XXX todo: NOT SURE IF CORRECT


            } // Else handle other status codes
            else if (httpCode.equals(
                    "400")) // bad request
            {
                System.out.println(" Bad Download Request -errCode 400");
            } else if (httpCode.equals(
                    "404")) // not found
            {
                System.out.println(" Requested Download File Not Found - errCode 404");
            } else if (httpCode.equals(
                    "505")) // HTTP version not supported
            {
                System.out.println(" HTTP version Not Supported  -errCode 505");
            }
        } catch (UnknownHostException e) {
            System.out.println("Unknown host");


        } catch (IOException e) {
            System.out.println("No I/O");
        }
            catch (IndexOutOfBoundsException ob) {
            System.out.println("Reached End of File");
            }

         finally {
            try {
                this.client.close();
            } catch (IOException ex) {
                ex.printStackTrace();
                Logger.getLogger(RequestFile.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    }

    public static void main(String[] args) {
        //RequestFile rFile = new RequestFile("C:\\Users\\Rudy\\share\\xmas.mp3");
       // rFile.requestFile("192.168.1.100");
       // rFile.download();
    }
}
